﻿using System;
using Matrix.Common;
using System.ComponentModel;

namespace Matrix.ViewModel
{
   public abstract class MatrixOperationBase : IMatrixOperation
   {
      #region IMatrixOperation Members
      public MatrixOperationBase(MatrixManager manager)
      {
         this.manager = manager;
         if (manager != null)
         {
            manager.MatrixSizeChanged += new EventHandler(manager_MatrixSizeChanged);
         }
      }

      void manager_MatrixSizeChanged(object sender, EventArgs e)
      {
         if (manager != null)
         {

         }
      }

      private MatrixManager manager;
      public IMatrixManagers Manager
      {
         get
         {
            return manager;
         }
      }

      public abstract void Process();

      private bool isValid;
      public abstract bool IsValid
      {
         get;
      }

      public abstract string OperationName
      {
         get;
      }

      #endregion

      #region INotifyPropertyChanged Members

      public event PropertyChangedEventHandler PropertyChanged;

      protected void OnPropertyChanged(string propertyName)
      {
         if (PropertyChanged != null)
         {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
         }
      }

      #endregion
   }

   public class AdditionOperation : MatrixOperationBase
   {
      public AdditionOperation(MatrixManager manager) : base(manager)
      {

      }

      public override void Process()
      {
         if (Manager != null)
         {
            var mat1 = Manager.FirstMatrix as MatrixInstance;
            if (mat1 == null)
            {
               return;
            }
            var mat2 = Manager.SecondMatrix as MatrixInstance;

            var result = mat1.MatrixElement + mat2.MatrixElement;

            var resultMatrix = Manager.ResultMatrix as MatrixInstance;
            if (resultMatrix == null)
            {
               return;
            }

            resultMatrix.MatrixElement = result;
         }
      }

      public override string OperationName
      {
         get
         {
            return "+";
         }
      }

      public override bool IsValid
      {
         get
         {
            if (this.Manager != null && this.Manager.FirstMatrix != null && this.Manager.SecondMatrix != null)
            {
               return this.Manager.FirstMatrix.ColumnSize == this.Manager.SecondMatrix.ColumnSize && this.Manager.FirstMatrix.RowSize == this.Manager.SecondMatrix.RowSize;
            }

            return false;
         }
      }
   }

   public class SubtractOperation : MatrixOperationBase
   {
      public SubtractOperation(MatrixManager manager)
         : base(manager)
      {

      }

      public override void Process()
      {
         if (Manager != null)
         {
            var mat1 = Manager.FirstMatrix as MatrixInstance;
            if (mat1 == null)
            {
               return;
            }
            var mat2 = Manager.SecondMatrix as MatrixInstance;

            var result = mat1.MatrixElement - mat2.MatrixElement;

            var resultMatrix = Manager.ResultMatrix as MatrixInstance;
            if (resultMatrix == null)
            {
               return;
            }

            resultMatrix.MatrixElement = result;
         }
      }

      public override string OperationName
      {
         get
         {
            return "-";
         }
      }

      public override bool IsValid
      {
         get
         {
            if (this.Manager != null && this.Manager.FirstMatrix != null && this.Manager.SecondMatrix != null)
            {
               return this.Manager.FirstMatrix.ColumnSize == this.Manager.SecondMatrix.ColumnSize && this.Manager.FirstMatrix.RowSize == this.Manager.SecondMatrix.RowSize;
            }

            return false;
         }
      }
   }

   public class MultiplyOperation : MatrixOperationBase
   {
      public MultiplyOperation(MatrixManager manager)
         : base(manager)
      {

      }

      public override void Process()
      {
         if (Manager != null)
         {
            var mat1 = Manager.FirstMatrix as MatrixInstance;
            if (mat1 == null)
            {
               return;
            }
            var mat2 = Manager.SecondMatrix as MatrixInstance;

            var result = mat1.MatrixElement * mat2.MatrixElement;

            var resultMatrix = Manager.ResultMatrix as MatrixInstance;
            if (resultMatrix == null)
            {
               return;
            }

            resultMatrix.MatrixElement = result;
         }
      }

      public override string OperationName
      {
         get
         {
            return "*";
         }
      }

      public override bool IsValid
      {
         get
         {
            if (this.Manager != null && this.Manager.FirstMatrix != null && this.Manager.SecondMatrix != null)
            {
               return this.Manager.FirstMatrix.ColumnSize == this.Manager.SecondMatrix.ColumnSize && this.Manager.FirstMatrix.RowSize == this.Manager.SecondMatrix.RowSize;
            }

            return false;
         }
      }
   }
}
